import json
import os
from typing import List, Dict

from PySide2.QtGui import QColor, QFont
from PySide2.QtWidgets import QWidget, QTableWidget, QTableWidgetItem

import Logger
import Util
from ExcelData import EData
from UiViewer import Ui_ViewerDialog
from lib import ExcelLibLoader
import lib.ExcelLibDefinition as Definition
from lib.ExcelLibDefinition import ExcelLibDefinition
from lib.ExcelLibDefinitionTable import ExcelLibDefinitionTable
from lib.ExcelLibDefinitionMain import ExcelLibDefinitionMain

ROW_STYLE_NORMAL: int = 0
ROW_STYLE_ADDED: int = 1
ROW_STYLE_REMOVED: int = 2
ROW_STYLE_MODIFY: int = 3

COLOR_BG_ADDED: QColor = QColor(222, 255, 222)
COLOR_BG_REMOVED: QColor = QColor(255, 210, 210)
COLOR_BG_MODIFY: QColor = QColor(255, 255, 222)

COLOR_FONT_ADDED: QColor = QColor(0, 180, 0)
COLOR_FONT_REMOVED: QColor = QColor(153, 153, 153)
COLOR_FONT_MODIFY: QColor = QColor(255, 120, 0)

COLPLUS_TXT: List[str] = ["旧表", "新表", "变更"]
COLPLUS_ORD_OLD: int = 0
COLPLUS_ORD_NEW: int = 1
COLPLUS_ORD_OP: int = 2


class ViewerDialog(QWidget, Ui_ViewerDialog):
    edata: EData
    logger: Logger

    def __init__(self):
        super(ViewerDialog, self).__init__()
        self.edata = EData()
        self.logger = Logger.Logger()

        self.ui = Ui_ViewerDialog()
        self.ui.setupUi(self)

    def show(self):
        print("打开发布UI")
        super(ViewerDialog, self).show()

    def resizeEvent(self, event):
        pass

    def moveEvent(self, event):
        pass

    def closeEvent(self, event):
        pass

    def __getTables(self, jsonFullPath):
        # 正式开始读表
        if not Util.isFileAndExists(jsonFullPath):
            self.logger.logError("你选择的数据文件不存在！")
            return None
        with open(jsonFullPath, 'r', encoding='utf8') as f:
            data = json.load(f)
        if data is None:
            self.logger.logError("你选择的数据文件读取错误！")
            return None
        headDic: dict = data.get("header")
        count: int = headDic["count"]
        if count is None:
            self.logger.logError("你选择的数据Head->count读取错误！")
            return None
        if count < 1:
            self.logger.logWarning("你选择的数据head表示内容为空！")
        self.logger.logNotice("读取文件：" + jsonFullPath + ", 表数据行数：" + str(count))
        tables: [] = data.get("data")
        if tables is None:
            self.logger.logError("你选择的数据表内容读取错误！")
            return None
        if type(tables) is List:
            self.logger.logError("你选择的数据表内容读取错误！")
            return None
        count2: int = len(tables)
        if count != count2:
            self.logger.logWarning("你选择的数据head记录数量与实际数量不一致，Head:" + str(count) + " Data:" + str(count2))
        if count2 < 1:
            self.logger.logWarning("你选择的数据内容为空！")
            return None
        return tables

    def viewJson(self, filepath: str, filename: str):

        # 正式开始读表
        jsonFullPath: str = os.path.join(filepath, filename)
        tables: [] = self.__getTables(jsonFullPath)
        if tables is None:
            return

        ls: QTableWidget = self.ui.listData
        ls.clear()
        # 先处理表头
        colNames: List[str] = []
        for (key, val) in tables[0].items():
            colNames.append(key)
        # self.initColumnListFile(colNames)
        Util.initColumnListFile(self.ui.listData, colNames, None, Util.HEADER_STYLE_GREEN)
        ls.setRowCount(len(tables))
        for row in range(0, len(tables)):
            rowData: Dict = tables[row]
            self.addRow(colNames, rowData, row)
        self.ui.listData.resizeColumnsToContents()

    def diffJson(self, filepathOrigin: str, filenameDiff: str, filename: str):
        # 正式开始读表
        definition1: ExcelLibDefinitionMain = Util.getDefinition(filepathOrigin)
        if definition1 is None:
            return

        definition2: ExcelLibDefinitionMain = Util.getDefinition(filenameDiff)
        if definition2 is None:
            return

        jsonFullPath1: str = os.path.join(filepathOrigin, filename)
        table1: [] = self.__getTables(jsonFullPath1)
        if table1 is None:
            return

        jsonFullPath2: str = os.path.join(filenameDiff, filename)
        table2: [] = self.__getTables(jsonFullPath2)
        if table2 is None:
            return

        # 先处理表头
        colNames: List[str] = []
        for (key, val) in table1[0].items():
            colNames.append(key)
        colNamesCmp: List[str] = []
        for (key, val) in table2[0].items():
            colNamesCmp.append(key)

        # 找出删除表列，与新增表列
        delCol: List[str] = []
        for i in range(0, len(colNames)):
            key = colNames[i]
            if table2[0][key] is None:
                delCol.append(key)
                self.logger.logWarning("检查出字段[" + key + "]已经删除。")
        newCol: [] = []
        for i in range(0, len(colNamesCmp)):
            key = colNamesCmp[i]
            if table1[0][key] is None:
                newCol.append(key)
                self.logger.logWarning("检查出新增了字段[" + key + "]。")
        if len(delCol) + len(newCol) > 0:
            self.logger.logError("字段有变动，不能比对！")
            return

        self.ui.listData.clear()

        # 找出主键列
        dfs: List[ExcelLibDefinition] = definition1.definitions
        mainKeys: dict = dict()
        onlyFilename = os.path.splitext(filename)[0]
        isListType:bool = False # 列表式没主键式数据表
        for df in dfs:
            if df.loadJson == onlyFilename:
                if df.loadType == Definition.LOAD_TYPE_LIST or df.loadType == Definition.LOAD_TYPE_MAP2LIST:
                    isListType = True
                for key in df.getMainKeys():
                    mainKeys[key] = key

        colPlus = COLPLUS_TXT.copy()
        colPlus.reverse()
        for i in range(0, len(colPlus)):
            colNames.insert(0, colPlus[i])

        if definition1.version > definition2.version:
            self.logger.logNotice("开始比较：(较旧)" + definition2.version + " <--> (较新)" + definition1.version)
            oldTable = table2
            newTable = table1
        else:
            self.logger.logNotice("开始比较：(较旧)" + definition1.version + " <--> (较新)" + definition2.version)
            oldTable = table1
            newTable = table2

        if isListType:
            allKeys: dict = dict()
            for i in range(len(COLPLUS_TXT), len(colNames)):
                allKeys[colNames[i]] = colNames[i]
            self.diffUniqueKeyTable(colNames, allKeys, oldTable, newTable)
        else:
            self.diffUniqueKeyTable(colNames, mainKeys, oldTable, newTable)

    def diffNoKeyTable(self, colNames: List[str], mainKeys: dict, tableOld: [], tableNew: []):
        """比对没有主键的表"""
        # 开始比对
        ls: QTableWidget = self.ui.listData
        Util.initColumnListFile(self.ui.listData, colNames, None, Util.HEADER_STYLE_GREEN)
        ls.setRowCount(len(tableOld) + len(tableNew))
        row: int = 0
        rowNew: int = 0
        # while isRun:
        for rowOld in range(0, len(tableOld)):
            rowDataOld: Dict = tableOld[rowOld]
            rowDataNew: Dict = tableNew[rowNew]
            ls.setItem(row, COLPLUS_ORD_OP, self.getItemEmpty())
            # 根据主键完全匹配找行
            index = self.findEqualMainKey(mainKeys, rowDataOld, tableNew, rowNew)
            if index < 0:
                # 这是在新表上找不到，则证明正行【已经被删除】
                self.addRow(colNames, rowDataOld, row, ROW_STYLE_REMOVED)
                self.logger.logNotice("第 " + str(row) + " 行数据被删除。")
                ls.setItem(row, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                ls.setItem(row, COLPLUS_ORD_OP, self.getItemDelete())
                row += 1
            else:
                # 如果找到的行是与当前比对行一致，则比较字段 (返回记录行移动指向行数)
                isSameData: bool = self.compareRow(colNames, rowDataOld, rowDataNew, row)
                if isSameData:
                    ls.setItem(row, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                    ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
                    row += 1
                else:
                    # 数据已经被【修改】
                    ls.setItem(row + 1, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                    ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
                    ls.setItem(row, COLPLUS_ORD_OP, self.getItemModify())
                    ls.setItem(row + 1, COLPLUS_ORD_OP, self.getItemBeforeMofify())
                    row += 2
                rowNew += 1

        ls.setRowCount(row)
        ls.resizeColumnsToContents()
        self.logger.logSuccess("比较文件完成。")

    def diffUniqueKeyTable(self, colNames: List[str], mainKeys: dict, tableOld: [], tableNew: []):
        """ 比对有主键的表"""
        # 开始比对
        ls: QTableWidget = self.ui.listData
        Util.initColumnListFile(self.ui.listData, colNames, None, Util.HEADER_STYLE_GREEN)
        ls.setRowCount(len(tableOld) + len(tableNew))
        row: int = 0
        rowNew: int = 0
        # while isRun:
        for rowOld in range(0, len(tableOld)):
            rowDataOld: Dict = tableOld[rowOld]
            rowDataNew: Dict = tableNew[rowNew]
            ls.setItem(row, COLPLUS_ORD_OP, self.getItemEmpty())
            # 根据主键完全匹配找行
            index = self.findEqualMainKey(mainKeys, rowDataOld, tableNew, rowNew)
            if index == rowNew:
                # 如果找到的行是与当前比对行一致，则比较字段 (返回记录行移动指向行数)
                isSameData: bool = self.compareRow(colNames, rowDataOld, rowDataNew, row)
                if isSameData:
                    ls.setItem(row, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                    ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
                    row += 1
                else:
                    # 数据已经被【修改】
                    ls.setItem(row + 1, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                    ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
                    ls.setItem(row, COLPLUS_ORD_OP, self.getItemModify())
                    ls.setItem(row + 1, COLPLUS_ORD_OP, self.getItemBeforeMofify())
                    row += 2
                rowNew += 1
            elif index < 0:
                # 这是在新表上找不到，则证明正行【已经被删除】
                self.addRow(colNames, rowDataOld, row, ROW_STYLE_REMOVED)
                self.logger.logNotice("第 " + str(row) + " 行数据被删除。")
                ls.setItem(row, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                ls.setItem(row, COLPLUS_ORD_OP, self.getItemDelete())
                row += 1
                # row1 += 1
            else:
                # 剩余情况就是新表在这之间【插入】了一些【新数据行】
                while rowNew < index:
                    rowDataAdd: Dict = tableNew[rowNew]
                    self.addRow(colNames, rowDataAdd, row, ROW_STYLE_ADDED)
                    self.logger.logNotice("第 " + str(row) + " 行数据新增一行。")
                    ls.setItem(row, COLPLUS_ORD_OLD, self.getItemEmpty())
                    ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
                    ls.setItem(row, COLPLUS_ORD_OP, self.getItemAdded())
                    row += 1
                    rowNew += 1
                rowDataNew: Dict = tableNew[rowNew]
                isSameData: bool = self.compareRow(colNames, rowDataOld, rowDataNew, row)
                if isSameData:
                    ls.setItem(row, COLPLUS_ORD_OLD, self.getItemOrd(rowOld))
                    ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
                    row += 1
                else:
                    ls.setItem(row, COLPLUS_ORD_OP, self.getItemModify())
                    ls.setItem(row + 1, COLPLUS_ORD_OP, self.getItemBeforeMofify())
                    row += 2
                rowNew = index + 1

        while rowNew<len(tableNew):
            rowDataAdd: Dict = tableNew[rowNew]
            self.addRow(colNames, rowDataAdd, row, ROW_STYLE_ADDED)
            self.logger.logNotice("第 " + str(row) + " 行数据新增一行。")
            ls.setItem(row, COLPLUS_ORD_OLD, self.getItemEmpty())
            ls.setItem(row, COLPLUS_ORD_NEW, self.getItemOrd(rowNew))
            ls.setItem(row, COLPLUS_ORD_OP, self.getItemAdded())
            row += 1
            rowNew += 1

        ls.setRowCount(row)
        ls.resizeColumnsToContents()
        self.logger.logSuccess("比较文件完成。")


    def compareRow(self, colNames: List[str], rowData1: Dict, rowData2: Dict, row):
        isSameData: bool = True
        for col in range(0, len(colNames)):
            key = colNames[col]
            for i in range(0, len(COLPLUS_TXT)):
                if key == COLPLUS_TXT[i]:
                    key = None
            if key is None:
                continue
            content1 = str(rowData1[key])
            content2 = str(rowData2[key])
            # 添加到表格
            item = QTableWidgetItem(content1)
            if content1 != content2:
                isSameData = False
                item.setTextColor(COLOR_FONT_REMOVED)
                item.setBackgroundColor(COLOR_BG_MODIFY)
                itemNew = QTableWidgetItem(content2)
                itemNew.setTextColor(COLOR_FONT_MODIFY)
                itemNew.setBackgroundColor(COLOR_BG_MODIFY)
                self.ui.listData.setItem(row, col, itemNew)
                self.ui.listData.setItem(row + 1, col, item)
                self.logger.logNotice("第 " + str(row) + " 行, [" + key + "]列有数据变更:" + content1 + " -> " + content2)
            else:
                self.ui.listData.setItem(row, col, item)
        return isSameData

    def addRow(self, colNames: List[str], rowData: Dict, row, style: int = ROW_STYLE_NORMAL):
        for col in range(0, len(colNames)):
            key = colNames[col]
            for i in range(0, len(COLPLUS_TXT)):
                if key == COLPLUS_TXT[i]:
                    key = None
            if key is None:
                continue
            content = str(rowData[key])
            item = QTableWidgetItem(content)
            if style == ROW_STYLE_ADDED:
                item.setBackgroundColor(COLOR_BG_ADDED)
            elif style == ROW_STYLE_REMOVED:
                item.setBackgroundColor(COLOR_BG_REMOVED)
            elif style == ROW_STYLE_MODIFY:
                item.setBackgroundColor(COLOR_BG_MODIFY)
            self.ui.listData.setItem(row, col, item)

    def findEqualMainKey(self, mainKeys: Dict, rowData1: Dict, table2: List, row2):
        for row in range(row2, len(table2)):
            t2: Dict = table2[row]
            isEqual: bool = True
            for key in mainKeys.values():
                if rowData1[key] != t2[key]:
                    isEqual = False
            if isEqual:
                return row
        return -1

    def getItemOrd(self, row):
        itemOrd: QTableWidgetItem = QTableWidgetItem(str(row))
        return itemOrd

    def getItemEmpty(self):
        itemEmpty: QTableWidgetItem = QTableWidgetItem(" ")
        return itemEmpty

    def getItemDelete(self):
        itemDeleted: QTableWidgetItem = QTableWidgetItem("已删除")
        itemDeleted.setBackgroundColor(COLOR_BG_REMOVED)
        itemDeleted.setTextColor(COLOR_FONT_REMOVED)
        return itemDeleted

    def getItemAdded(self):
        itemAdded: QTableWidgetItem = QTableWidgetItem("新增")
        itemAdded.setBackgroundColor(COLOR_BG_ADDED)
        itemAdded.setTextColor(COLOR_FONT_ADDED)
        return itemAdded

    def getItemModify(self):
        itemModify: QTableWidgetItem = QTableWidgetItem("修改")
        itemModify.setBackgroundColor(COLOR_BG_MODIFY)
        itemModify.setTextColor(COLOR_FONT_MODIFY)
        return itemModify

    def getItemBeforeMofify(self):
        itemBeforeMofify: QTableWidgetItem = QTableWidgetItem("原始值")
        itemBeforeMofify.setBackgroundColor(COLOR_BG_MODIFY)
        itemBeforeMofify.setTextColor(COLOR_FONT_REMOVED)
        return itemBeforeMofify